package com.uzhie.media;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by TangFei on 2018/7/25.
 */
public class MediaServer {

    private Logger logger = Logger.getLogger(this.getClass());
    private int port;
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private ServerBootstrap serverBootstrap;
    private ChannelInboundHandlerAdapter channelInboundHandlerAdapter;
    private boolean isRunning = false;

    public void setPort(int port) {
        this.port = port;
    }

    public void setBossGroup(EventLoopGroup bossGroup) {
        this.bossGroup = bossGroup;
    }

    public void setWorkerGroup(EventLoopGroup workerGroup) {
        this.workerGroup = workerGroup;
    }

    public void setServerBootstrap(ServerBootstrap serverBootstrap) {
        this.serverBootstrap = serverBootstrap;
    }

    public void setChannelInboundHandlerAdapter(ChannelInboundHandlerAdapter channelInboundHandlerAdapter) {
        this.channelInboundHandlerAdapter = channelInboundHandlerAdapter;
    }

    /**
     * 启动流媒体服务
     */
    public void init() {
        logger.trace("启动流媒体服务");
        Thread thread = new Thread(() -> runMedia(), "Media-Thread");
        thread.start();
    }

    /**
     * 容器退出时 停止流媒体服务线程
     *
     * @throws InterruptedException
     */
    public void destroy() throws InterruptedException {
        logger.trace("关闭流媒体服务");
        stop();
    }

    private synchronized void runMedia() {
        try {
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            // 消息体最大长度为 65535 字节
                            ch.pipeline().addLast(new MediaByteDecoder(integerToBytes(MediaConstant.SPLIT_SYMBOL), 0XFFFF));
                            ch.pipeline().addLast(new MediaByteEncoder(integerToBytes(MediaConstant.SPLIT_SYMBOL)));
                            ch.pipeline().addLast(channelInboundHandlerAdapter);
                        }
                    });
            serverBootstrap.bind(port).sync();
            isRunning = true;
            logger.trace("media TCP server is running on port " + port + " 流媒体服务启动成功！");
        } catch (Exception e) {
            logger.trace("media TCP server not running on port " + port + "启动流媒体服务异常！", e);
        } finally {
            logger.trace("流媒体服务启动完成！");
        }
    }

    private void stop() {
        try {
            if (isRunning) {
                bossGroup.shutdownGracefully().sync();
                workerGroup.shutdownGracefully().sync();
                isRunning = false;
                logger.trace("关闭 流媒体 服务成功");
            } else {
                logger.trace("流媒体 服务未启动！");
            }
        } catch (InterruptedException e) {
            logger.trace("关闭 流媒体 服务失败！", e);
        } finally {
            logger.trace("关闭 流媒体 服务完成！");
        }

    }

    private byte[] integerToBytes(int value) {
        byte[] bytes = new byte[4];
        bytes[0] = (byte) (value >>> 24 & 0XFF);
        bytes[1] = (byte) (value >> 16 & 0XFF);
        bytes[2] = (byte) (value >> 8 & 0XFF);
        bytes[3] = (byte) (value & 0XFF);
        return bytes;
    }

    public static void main(String[] args) throws Exception {
        ApplicationContext ct = new ClassPathXmlApplicationContext("classpath:spring-media.xml");
    }

}
